#include "server.h"

int main(int argc, char *argv[]) {
    ARGS_CHECK(argc, 3);
    
    /* 创建线程池 */
    threadPool_t threadPool;
    initThreadPool(&threadPool, 4);

    /* TCP 连接 */
    int socketFd;
    tcpServerInit(argv[1], argv[2], &socketFd);

    /* 监听 */
    int epollFd = epoll_create(1);
    threadPool.epollFd = epollFd;
    makeWorkers(&threadPool);
    epollAdd(epollFd, socketFd);
    struct epoll_event eventArr[10];
    while (1) {
        int readyCount = epoll_wait(epollFd, eventArr, 10, -1);
        ERROR_CHECK(readyCount, -1, "epoll_wait");
        for (int i = 0; i < readyCount; ++i) { 
            
            /* 事件一: 有新连接就先验证密码再增加监听 */
            if (eventArr[i].data.fd == socketFd) {
                
                struct sockaddr_in clientAddr;
                int netFd = acceptConnection(socketFd, &clientAddr);
                printf("New Connection\n\n");
                strcpy(threadPool.pathBuffer[netFd], "/");
                char ip[128] = {0};
                inet_ntop(AF_INET, &clientAddr.sin_addr.s_addr, ip, sizeof(ip));
                char buffer[512] = {0};
                sprintf(buffer, "ip = %s, port = %d", ip, ntohs(clientAddr.sin_port));
                LOG_WRITE(buffer);
                MYSQL *mysql = mysql_init(NULL);
                MYSQL *ret = mysql_real_connect(mysql, "127.0.0.1", "root", "123", "myCloud", 0, NULL, 0);
                if (!ret) {
                    fprintf(stderr,"mysql_real_connect: %s\n", mysql_error(mysql));
                    return 0;
                }
                
                while (1) {
                    char s[128] = {0};
                    ssize_t recvRet = recvMessageFromClient(netFd, s, sizeof(s));
                    if (!recvRet) {
                        close(netFd);
                        break;
                    }
                    puts(s);

                    /* 登录 */
                    if (strcmp(s, "0") == 0) {
                        user_t user;
                        memset(&user, 0, sizeof(user));
                        ssize_t recvRet = recv(netFd, &user, sizeof(user), 0);
                        ERROR_CHECK(recvRet, -1, "recv");
                        if (!recvRet) {
                            close(netFd);
                            break;
                        }
                        int loadingRet = loading(user, mysql);
                        if (loadingRet == 0) {
                            ssize_t sendRet = send(netFd, "1", 1, 0);
                            ERROR_CHECK(sendRet, -1, "send");
                            memset(threadPool.userBuffer[netFd], 0, sizeof(threadPool.userBuffer[netFd]));
                            strcpy(threadPool.userBuffer[netFd], user.userName);
                            strcpy(threadPool.pathBuffer[netFd], "/");
                            epollAdd(epollFd, netFd);
                            break;
                        } else if (loadingRet == -999) {
                            ssize_t sendRet = send(netFd, "0", 1, 0);
                            ERROR_CHECK(sendRet, -1, "send");
                        } else {
                            ssize_t sendRet = send(netFd, "2", 1, 0);
                            ERROR_CHECK(sendRet, -1, "send");
                        }
                    
                    /* 注册 */
                    } else if (strcmp(s, "1") == 0) {

                        user_t user;
                        memset(&user, 0, sizeof(user));
                        ssize_t recvRet = recv(netFd, &user, sizeof(user), 0);
                        ERROR_CHECK(recvRet, -1, "recv");
                        if (!recvRet) {
                            close(netFd);
                            break;
                        }
                        puts(user.userName);
                        puts(user.passwd);
                        int signRet = registration(user, mysql);
                        if (signRet == 1) {
                            send(netFd, "1", 1, 0);
                            memset(threadPool.userBuffer[netFd], 0, sizeof(threadPool.userBuffer[netFd]));
                            strcpy(threadPool.userBuffer[netFd], user.userName);
                            int inret = insertRoot(mysql, user.userName);
                            if(inret != 0){
                                fprintf(stderr,"Failed to create root directory\n");
                                send(netFd,"0",1,0);
                                return 0;
                            }
                            memset(threadPool.pathBuffer[netFd], 0, sizeof(threadPool.pathBuffer[netFd]));
                            strcpy(threadPool.pathBuffer[netFd], "/");
                            epollAdd(epollFd, netFd);
                            break;
                        } else {
                            send(netFd, "0", 1, 0);            
                        }
                    }
                }

            /* 事件二: 有任务到来就加入队列, 并唤醒一个线程 */    
            } else {
                
                pthread_mutex_lock(&threadPool.mutex);
                enQueue(&threadPool.taskQueue, eventArr[i].data.fd);

                /* 注意! 必须先移除监听再唤醒线程, 然后在线程做完任务后添加监听 */
                /* 否则多个线程会接到同一个任务 */
                epollDelete(epollFd, eventArr[i].data.fd);
                pthread_cond_signal(&threadPool.cond);

                pthread_mutex_unlock(&threadPool.mutex);
            }
        }
    }
    return 0;
}
